﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Observable;
using System.Collections;
using System.ComponentModel;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

namespace SpeakupBackend.Themes
{
    [Serializable]
    public class GroupThemeCollection: IEnumerable<GroupTheme>, IEnumerable, INotifyPropertyChanged 
    {
        static int IndexOf(Level level)
        {
            return level.LevelNumber - Level.MinValidLevelNumber;
        }

        static int IndexOf(GroupThemeName name)
        {
            /* rely on the fact that names are sequential */
            return (int)name;
        }

        static readonly int LevelCount = Level.MaxValidLevelNumber - Level.MinValidLevelNumber + 1;
        static readonly int NameCount = Enum.GetValues(typeof(GroupThemeName)).Length;

        GroupTheme [,] ThemeTable;
        
        public GroupThemeCollection()
        {
            ThemeTable = new GroupTheme[LevelCount, NameCount];
                        
            foreach(GroupThemeName name in Enum.GetValues(typeof(GroupThemeName)))
            {
                foreach (Level level in Level.GetLevels())
                {
                    GroupTheme theme = new GroupTheme(name, level);
                    theme.PropertyChanged += OnPropertyChanged;

                    ThemeTable[IndexOf(level), IndexOf(name)] = theme;
                }
            }
        }

        public IEnumerable<GroupTheme> this[GroupThemeName name]
        {
            get
            {
                foreach (Level level in Level.GetLevels())
                {
                    yield return ThemeTable[IndexOf(level), IndexOf(name)];
                }
            }
        }

        public IEnumerable<GroupTheme> this[Level level]
        {
            get
            {
                foreach (GroupThemeName name in Enum.GetValues(typeof(GroupThemeName)))
                {
                    yield return ThemeTable[IndexOf(level), IndexOf(name)];
                }
            }
        }

        public GroupTheme this[GroupThemeName name, Level level]
        {
            get
            {
                return ThemeTable[IndexOf(level), IndexOf(name)];
            }
        }

        public GroupTheme this[Level level, GroupThemeName name]
        {
            get
            {
                return this[name, level];
            }
        }

        public IEnumerator<GroupTheme> GetEnumerator()
        {
            foreach (Level level in Level.GetLevels())
            {
                foreach (GroupThemeName name in Enum.GetValues(typeof(GroupThemeName)))
                {
                    yield return ThemeTable[IndexOf(level), IndexOf(name)];
                }
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return ThemeTable.GetEnumerator();
        }


        [field:NonSerialized]
        public event PropertyChangedEventHandler PropertyChanged;

        void OnPropertyChanged(Object source, PropertyChangedEventArgs args)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(source, args);
            }
        }

        [OnDeserialized]
        void OnDeserialized(StreamingContext context)
        {
            foreach (var theme in ThemeTable)
            {
                theme.PropertyChanged += OnPropertyChanged;
            }
        }

        #region Binary serialization

        public void Save(String fileName)
        {
            BinaryFormatter formatter = new BinaryFormatter();
            using (FileStream fileStream = new FileStream(fileName, FileMode.Create))
            {
                formatter.Serialize(fileStream, this);
            }
        }

        public static GroupThemeCollection Load(String fileName)
        {
            BinaryFormatter formatter = new BinaryFormatter();
            using (FileStream fileStream = new FileStream(fileName, FileMode.Open))
            {
                return (GroupThemeCollection)formatter.Deserialize(fileStream);
            }
        }

        public void ReloadFrom(String fileName)
        {
            foreach (GroupTheme theme in ThemeTable)
            {
                theme.PropertyChanged -= OnPropertyChanged;
            }

            GroupThemeCollection loadedCollection = Load(fileName);
            ThemeTable = loadedCollection.ThemeTable;

            foreach (GroupTheme theme in ThemeTable)
            {
                theme.PropertyChanged += OnPropertyChanged;
            }
        }

        #endregion
    }
}
